#include "memlayout.h"

// UART寄存器偏移量定义，(UART0 + 偏移量)即可访问对应寄存器
#define RHR 0 // Receive Holding Register，用于读取接收到的数据
#define THR 0 // Transmit Holding Register，用于写入要发送的数据
#define LSR 5 // Line Status Register，用于检查UART状态

// LSR寄存器中的状态位定义
#define LSR_TX_IDLE (1 << 5) // LSR第5位，为1表示发送缓冲区为空，可以继续发送
#define LSR_RX_READY (1 << 0) // LSR第0位，为1表示RHR有数据可读

// 从指定的寄存器读取一个字符
static inline char read_reg(int reg) {
    // volatile关键字防止编译器优化对硬件寄存器的访问
    return *(volatile char *)(UART0 + reg); 
}

// 向指定的寄存器写入一个字符
static inline void write_reg(int reg, char c) {
    *(volatile char *)(UART0 + reg) = c;
}

// 初始化UART控制器
void uartinit() {
    // 在QEMU模拟器中，UART控制器默认已经配置好了，所以这里不需要做任何初始化
}

// 发送单个字符（同步发送）
void uartputc(char c) {
    // 等待直到发送缓冲区为空（即上一次发送完成）
    while((read_reg(LSR) & LSR_TX_IDLE) == 0);
    // 将字符写入发送保持寄存器
    write_reg(THR, c);
}

// 输出字符串，以'\0'结尾
void uartputs(char *s) {
    // 循环输出字符串中的每个字符，直到遇到结束符
    while(*s) {
        uartputc(*s++);
    }
}

//接收一个字符
char uartgetc(void) {
    //等待RHR数据就绪
    while((read_reg(LSR) & LSR_RX_READY) == 0);
    return read_reg(RHR);
}

//读取字符串到缓冲区
void uartgets(char *buf) {
    char c;
    int i = 0;
    while(1) {
        c = uartgetc();
        
        //回车或换行结束输入
        if(c == '\r' || c == '\n') {
            uartputc('\n');
            buf[i] = '\0';  //字符串结束符
            break;
        }
        //退格删除字符
        else if(c == '\b' || c == 0x7f) {
            if(i > 0) {
                i--;
                uartputs("\b \b");  //显示退格效果，光标退回并输出空格替换，光标再回到空格之前
            }
        }
        //普通字符
        else {
            buf[i++] = c;
            uartputc(c);  //回显字符
        }
    }
}